#include <stdlib.h>
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <fcntl.h>
#include <math.h>
#include <errno.h>
#include <sys/time.h>
#include <pthread.h>
#include <signal.h>
#include <semaphore.h>
#include <sched.h>
#include "quant.h"
#ifdef IPP
#include <ipp.h>
#include <ippdefs.h>
#endif








/*............................................................ POSIX thread declarations and scheduling attribute.................................*/
pthread_t threads[4];
pthread_t main_thread;
pthread_attr_t rt_sched_attr;
pthread_attr_t main_sched_attr;
int rt_max_prio, rt_min_prio, min, old_ceiling, new_ceiling;
struct sched_param rt_param;
struct sched_param nrt_param;
struct sched_param main_param;

typedef struct _threadParamsType
{
	int threadID;
	unsigned int microsecs;
	double digestsPerSec;
} threadParamsType;
#define FALSE 0
#define SCHED_POLICY SCHED_FIFO
pthread_t threads[4];
pthread_t tstThreadHandle[4];
threadParamsType threadParams[4];
pthread_attr_t rt_sched_attr;
pthread_attr_t tstThread_sched_attr;
int rt_max_prio, rt_min_prio, min, old_ceiling, new_ceiling;
struct sched_param rt_param;
struct sched_param nrt_param;
struct sched_param tstThread_param;
int threadActiveCnt=0, threadActive=FALSE;
sem_t startIOWorker[1],startProcessWorker;







/*....................................................Threading Functions- Set scheduling Policy.............................................................*/

/*void print_scheduler(void)
{
   int schedType;

   schedType = sched_getscheduler(getpid());

   switch(schedType)
   {
     case SCHED_FIFO:
	   printf("Pthread Policy is SCHED_FIFO\n");
	   break;
     case SCHED_OTHER:
	   printf("Pthread Policy is SCHED_OTHER\n");
       break;
     case SCHED_RR:
	   printf("Pthread Policy is SCHED_OTHER\n");
	   break;
     default:
       printf("Pthread Policy is UNKNOWN\n");
   }
}


void setSchedPolicy(void)
{
   int rc, scope;

   // Set up scheduling
   //
   print_scheduler();

   pthread_attr_init(&rt_sched_attr);
   pthread_attr_init(&tstThread_sched_attr);
   pthread_attr_setinheritsched(&rt_sched_attr, PTHREAD_EXPLICIT_SCHED);
   pthread_attr_setschedpolicy(&rt_sched_attr, SCHED_POLICY);
   pthread_attr_setinheritsched(&tstThread_sched_attr, PTHREAD_EXPLICIT_SCHED);
   pthread_attr_setschedpolicy(&tstThread_sched_attr, SCHED_POLICY);

   rt_max_prio = sched_get_priority_max(SCHED_POLICY);
   rt_min_prio = sched_get_priority_min(SCHED_POLICY);

   rc=sched_getparam(getpid(), &nrt_param);
   rt_param.sched_priority = rt_max_prio;

#ifdef SET_SCHED_POLICY
   rc=sched_setscheduler(getpid(), SCHED_POLICY, &rt_param);

   if (rc)
   {
       printf("ERROR: sched_setscheduler rc is %d\n", rc);
       perror("sched_setscheduler");
   }
   else
   {
       printf("SCHED_POLICY SET: sched_setscheduler rc is %d\n", rc);
   }

   print_scheduler();
#endif

   printf("min prio = %d, max prio = %d\n", rt_min_prio, rt_max_prio);
   pthread_attr_getscope(&rt_sched_attr, &scope);

   if(scope == PTHREAD_SCOPE_SYSTEM)
     printf("PTHREAD SCOPE SYSTEM\n");
   else if (scope == PTHREAD_SCOPE_PROCESS)
     printf("PTHREAD SCOPE PROCESS\n");
   else
     printf("PTHREAD SCOPE UNKNOWN\n");

   rt_param.sched_priority = rt_max_prio-1;
   pthread_attr_setschedparam(&rt_sched_attr, &rt_param);
   tstThread_param.sched_priority = rt_max_prio;
   pthread_attr_setschedparam(&tstThread_sched_attr, &tstThread_param);
}





*/




/*.................................................................The Read from File function.....................................................*/

void IOread ()
{
int FrameCount=0,num=0000;
char *read_filename;
do
{
	sem_wait(&startIOWorker[0]);
	read_filename[0] = '\0';
	strcat (read_filename, "Input_Frames/Frame");
	num=num+FrameCount;
	strcat (read_filename, num);
	strcat (read_filename, ".ppm");
	printf("\nRead Filename %s\n", read_filename);
	
	int fdin;
	if((fdin = open(read_filename, O_RDONLY, 0644))<0)
	printf("error opening file\n");
	int bytesRead=0, bytesLeft,i,j;

    	bytesLeft=21;

    	//printf("Reading header\n");

    	do
    	{
     	   //printf("bytesRead=%d, bytesLeft=%d\n", bytesRead, bytesLeft);
      	  bytesRead=read(fdin, (void *)quant[FrameCount].header, bytesLeft);
       	 bytesLeft -= bytesRead;
   	 } while(bytesLeft > 0);
	
   	 quant[FrameCount].header[21]='\0';

   	 //printf("header = %s\n", header);
   	 // printf("header = %s\n", header[1]);

   	 // Read RGB data
   	     		for(i=0; i<2073600; i++)
    			{
       			 	read(fdin, (void *)&quant[FrameCount].R[i], 1); quant[FrameCount].convR[i]=quant[FrameCount].R[i];
        			read(fdin, (void *)&quant[FrameCount].G[i], 1); quant[FrameCount].convG[i]=quant[FrameCount].G[i];
        			read(fdin, (void *)&quant[FrameCount].B[i], 1); quant[FrameCount].convB[i]=quant[FrameCount].B[i];
	
    			}	
    	
     close(fdin); 
     sem_post(&startProcessWorker); 
} while (FrameCount<FRAMECOUNT);
}


/*....................................................................The Write to File function.....................................................*/
void IOwrite()

{

int fdout,i,j,dimx=1920,dimy=1080,r1,r2,r3;
 //printf("\nhere\n");
int FrameCount=0,num=0000;
char *write_filename;
do
{
	write_filename[0] = '\0';
	strcat (write_filename, "Output_Frames/Frame");
	num=num+FrameCount;
	strcat (write_filename, num);
	strcat (write_filename, ".ppm");
	printf("\nWrite Filename %s\n", write_filename);
 	FILE *fp = fopen(write_filename, "wb");
 	
    
	(void) fprintf(fp, "P6\n%d %d\n255\n", dimx, dimy);

    	for(i=0; i<2073600; i++)
    	{
    		UINT8 color[3];
		color[0]=quant[FrameCount].convR[i];
		color[1]=quant[FrameCount].convG[i];
		color[2]=quant[FrameCount].convB[i];
	
		(void)fwrite(color,3,1,fp);
	}
   (void)fclose(fp);
    } while (FrameCount<FRAMECOUNT);
}

void Frameprocess (int Frameprocpoint)
{
colorquant(quant[Frameprocpoint]);
sharprof(quant[Frameprocpoint]);
}


int main()
{
	
    	int i, j,fdout,fdin,rc,rc1,rc2,Framepointer=0;
   	sem_init (&startIOWorker[0],0,4);
	sem_init(&startProcessWorker,0,30);
	rc2 = pthread_create(&threads[2],NULL,IOread,NULL);
	printf("\n30 frames in\n");
	sem_wait(&startProcessWorker);
	do
	{
	rc = pthread_create(&threads[0],NULL,Frameprocess, &Framepointer);
	Framepointer++;
	rc1 = pthread_create(&threads[1],NULL,Frameprocess, &Framepointer);
	Framepointer++;
	sem_post(&startIOWorker[0]);
	sem_post(&startIOWorker[0]);
	} while (Framepointer<FRAMECOUNT);
	pthread_join(threads[0],0);
	pthread_join(threads[1],0);
	rc2 = pthread_create(&threads[3],NULL,IOwrite,NULL);
}

